﻿using System;
using System.Collections.Generic;
using System.IO;
using Velocity4Net.Ctx;
using Velocity4Net.Runtime.Parser;
using Velocity4Net.Runtime.Parser.Node;
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace Velocity4Net.Runtime.Directives.Contrib
{
















    /**
     * The #for directive provides the behavior of the #foreach directive but also
     * provides an 'index' keyword that allows the user to define an optional index variable
     * that tracks the loop iterations. e.g.; #for($user in $users index $i).
     * As $user iterates through $users the index reference $i will be equal to
     * 0, 1, 2, etc..
     * @see org.apache.velocity.runtime.directive.Foreach
     */
    public class For : Foreach
    {
        protected String counterName;
        protected int counterInitialValue;

        public String getName()
        {
            return "for";
        }

        public int getType()
        {
            return BLOCK;
        }

        public void init(RuntimeServices rs, InternalContextAdapter context, Node node)
        {
            base.init(rs, context, node);
            // If we have more then 3 argument then the user has specified an
            // index value, i.e.; #foreach($a in $b index $c)
            if (node.jjtGetNumChildren() > 4)
            {
                // The index variable name is at position 4
                counterName = ((ASTReference)node.jjtGetChild(4)).getRootString();
                // The count value always starts at 0 when using an index.
                counterInitialValue = 0;
            }
        }


        public override bool render(InternalContextAdapter context, TextWriter writer, Node node)
        {
            Object c = context.get(counterName);
            context.put(counterName, counterInitialValue);
            try
            {
                return base.render(context, writer, node);
            }
            finally
            {
                if (c != null)
                {
                    context.put(counterName, c);
                }
                else
                {
                    context.remove(counterName);
                }
            }
        }


        protected void renderBlock(InternalContextAdapter context, TextWriter writer, Node node)
        {
            Object count = context.get(counterName);
            if (count is Number)
            {
                context.put(counterName, ((Number)count).intValue() + 1);
            }
            super.renderBlock(context, writer, node);
        }

        /**
         * We do not allow a word token in any other arg position except for the 2nd
         * since we are looking for the pattern #foreach($foo in $bar).
         */
        public void checkArgs(List<int> argtypes, Token t,
            String templateName)
        {
            base.checkArgs(argtypes, t, templateName);

            // If #foreach is defining an index variable make sure it has the 'index
            // $var' combo.
            if (argtypes.Count > 3)
            {
                if (argtypes[3] != ParserTreeConstants.JJTWORD)
                {
                    throw new MacroParseException(
                        "Expected word 'index' at argument position 4 in #foreach",
                        templateName, t);
                }
                else if (argtypes.Count == 4
                    || argtypes[4] != ParserTreeConstants.JJTREFERENCE)
                {
                    throw new MacroParseException(
                        "Expected a reference after 'index' in #foreach", templateName, t);
                }
            }
        }
    }
}